﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace HobSoft.SoccerBet2014.Domain.Implementation
{
    using Core;
    using Models.Core;
    using SoccerBet2014.Common.Queryable;
    public abstract class ReadonlyBinaryRepository<T, K> : IReadonlyRepository<T>, IUniKeyReadRepository<T>
        where T : class, IModel
    {
        protected ConcurrentDictionary<K, T> BinModels
        {
            get
            {
                return BinaryContext.Current.Get<T, K>();
            }
        }

        protected abstract Func<T, K> FindKey { get; }

        public virtual void Initialize()
        {
            BinaryContext.Current.Initialize<T, K>();
        }

        public virtual T Get(params object[] id)
        {
            T result = default(T);
            if (id.Length == 0) return null;
            K key = (K)id[0];
            if (BinModels.TryGetValue(key, out result))
                return result;
            return null;
        }

        public virtual IList<T> GetMany(Expression<Func<T, bool>> predicate)
        {
            if (predicate == null)
                throw new ArgumentNullException("predicate", "need predicate");
            return BinModels.Values.AsQueryable().Where(predicate).ToList();
        }

        public virtual IList<T> GetMany(Expression<Func<T, bool>> predicate, params ISortExpression<T>[] sortExpression)
        {
            if (predicate == null)
                throw new ArgumentNullException("predicate", "need predicate");
            if (sortExpression == null)
                throw new ArgumentNullException("sortExpression", "need sortExpression");
            return BinModels.Values.AsQueryable().Where(predicate).Sort(sortExpression).ToList();
        }

        public virtual IList<T> GetMany(ISortExpression<T>[] sortExpression, params object[] keys)
        {
            if (keys == null)
                throw new ArgumentNullException("keys", "need keys");
            if (sortExpression == null)
                throw new ArgumentNullException("sortExpression", "need sortExpression");
            if (!keys.Any()) return null;

            var query = from m in BinModels
                        join k in keys on m.Key equals k
                        select m.Value;
            return query.AsQueryable().Sort(sortExpression).ToList();
        }

        public virtual IList<T> GetMany(params object[] keys)
        {
            if (keys == null)
                throw new ArgumentNullException("keys", "need keys");
            if (!keys.Any()) return null;

            var query = from m in BinModels
                        join k in keys on m.Key equals k
                        select m.Value;
            return query.ToList();
        }
    }
}
